import config from "@/config/config.js";
import utils from '@/utils/utils';
import store from "@/store";
import clStorage from "@/utils/storage";


/** 网络请求
 * 封装成promise 抹平fail平台差异， res.data.success不为true自动报错并进入promise catch
 * uni.request的promise模式catch时不方便处理，自己用回调封装成promise
 * 微信环境405等http错误走的success回调，支付宝走的fail
 * @param {string} url
 * @param {Object} options.data 请求数据
 * @param {Boolean} options.noToast 请求失败是否不自动报错
 * @param {Boolean} options.showLoading 是否显示loading
 * @param {Boolean} options.noEncrypt 是否不加密
 * @param {string} encryptKey 加密key
 * @param {Boolean} options.isPrefix 是否前缀
 * @param {Boolean} dataothEncrypt dataoth是否加密
 * @params {*} rest 其他uni.request参数，如data, header, method默认： POST
 * @param {*} [{ data, noToast, showLoading, noEncrypt, encryptKey, isPrefix, dataothEncrypt, ...rest
 */
function request(
    url,
    {data, noToast, showLoading, noEncrypt, encryptKey, isPrefix, dataothEncrypt, ...rest} = {},
    methodType = 'POST'
) {
    showLoading &&
    uni.showLoading({
        title: '加载中',
    });

    const openEncrypt = !noEncrypt && config.isEncrypt;
    const {reversetime, time} = utils.getReverseTime();
    const newEncryptKey = encryptKey || 'zzz' + time;
    let newData = {};

    //加上全局通用
    data = {
        // userCode: store.state.baseInfo.userCode,
        // clAcessToken: store.state.baseInfo.clAccessToken,
        ...(data || {}),
    };

    // 处理历史遗留问题，赋值
    if (openEncrypt) {
        if (config.isLog) {
            console.log(`${url}`, data, JSON.stringify(data));
        }
        newData = encodeURIComponent(encryptByAES(JSON.stringify(data), newEncryptKey));
    } else {
        newData = data;
    }

    return new Promise((resolve, reject) => {
        // #ifdef H5
        isPrefix = true;
        url = '/dev-api' + url;
        // #endif
        uni.request({
            url: isPrefix ? url : config.getEnvConfig().apiPrefix + url,
            data: newData,
            dataType: 'text',
            header: setRequestHeader(data, reversetime),
            method: methodType, // PUT DELETE GET
            // 微信环境405等http错误也会进此回调
            success: res => {
                if (res.statusCode === 200) {
                    if (openEncrypt) {
                        res.data = decryptByAES(res.data, newEncryptKey);
                    }
                    if (dataothEncrypt) {
                        let data = JSON.parse(res.data);

                        if (!data.loginFlag === 'success') {
                            return reject({
                                ...res,
                                data: JSON.parse(res.data),
                            });
                        }

                        res.data = decryptByAES(data.bizData, config.aesKeyDatath);
                    }
                    // console.log(`${url}`, res.data);
                    res.data = JSON.parse(res.data);
                    if (config.isLog) {
                        console.log(`${url}`, res.data);
                    }
                    resolve(res);
                } else if (res.statusCode === 401) {
                    const nowDate = new Date();
                    const saveDate = store.state.baseInfo.savedTime;
                    if (!saveDate || nowDate - saveDate > 10 * 1000) {
                        store.dispatch('baseInfo/setBaseInfo', {
                            savedTime: nowDate,
                        });
                        // 未登录时候
                        utils.navigateToLogin()
                    }
                    reject(res);
                } else {
                    reject(res);
                }
            },
            fail: err => {
                console.log("err:" + JSON.stringify(err))
                // #ifdef MP-ALIPAY
                if (err.statusCode === 401) {
                    const nowDate = new Date();
                    const saveDate = store.state.baseInfo.savedTime;
                    if (!saveDate || nowDate - saveDate > 10 * 1000) {
                        store.dispatch('baseInfo/setBaseInfo', {
                            savedTime: nowDate,
                        });
                        // 未登录时候
                        utils.navigateToLogin()
                    }
                }
                // #endif
                reject(err);
            },
            ...rest,
        });
    }).then(
        res => {
            const data = res.data;
            showLoading && uni.hideLoading();
            if (data.code === 200) {
                return Promise.resolve(data);
            }
            if (!noToast) {
                utils.toast(
                    (data.msg && `${data.msg}${data.errCode ? '(' + data.errCode + ')' : ''}`) ||
                    data.data ||
                    config.serverErrorText
                );
            }
            //服务端返回errMsg, Promise返回reject
            return Promise.reject(data);
        },
        err => {
            showLoading && uni.hideLoading();
            if (!noToast) {
                if (err.statusCode) {
                    utils.toast(config.httpErrortText(err.statusCode));
                } else {
                    utils.toast(config.networkErrorText);
                }
            }
            return Promise.reject(err);
        }
    );
}

/**签名 */
function getSignTxt(str, pri) {
    if (!str || !pri) {
        return;
    }
    let signTxt;

    const privateKey = `test${pri}`;
    const signature = new Jsrsasign.KJUR.crypto.Signature({
        alg: 'SHA256withRSA',
        prvkeypem: privateKey,
    });
    signature.updateString(str);
    signTxt = Jsrsasign.hextob64(signature.sign());

    return signTxt;
}

/**生成请求头
 * @param {string} param 签名
 * @param {Number} cltime 时间戳
 */
function setRequestHeader(param, cltime) {
    const privateKey = store.state.baseInfo.privateKey || '';
    const token = clStorage.getAccessToken() || '';
    //请求参数签名加密
    const sign = getSignTxt(JSON.stringify(param), privateKey);

    let reqHeader = {};

    // #ifdef MP-ALIPAY
    reqHeader['terminal-type'] = 'alimini';
    // #endif

    // #ifdef MP-WEIXIN
    reqHeader['terminal-type'] = 'weixinmini';
    // #endif

    if (token) {
        reqHeader['Authorization'] = `Bearer  ${token}`;
    }

    return {
        cltime, // 反转13位时间戳
        'client-app': config.clientApp,
        ...reqHeader,
        ua: 'clText',
        sign, // 请求签名
    };
}

export default request;

